#pragma once
#include "RenderGraphResource.h"
#include "Runtime/BattleFirePrefix.h"
#include "Runtime/CGI/CGIRenderTarget.h"
#include "Runtime/CGI/CGITexture.h"
#include "Runtime/CGI/ExclusiveDepthStencil.h"
#include "Runtime/Math/Vector2D.h"

namespace Alice{
	// enum instead of bool to get better visibility when we pass around multiple bools, also allows for easier extensions
	namespace ETranslucencyPass
	{
		enum Type : int
		{
			TPT_TranslucencyStandard,
			TPT_TranslucencyStandardModulate,
			TPT_TranslucencyAfterDOF,
			TPT_TranslucencyAfterDOFModulate,
			TPT_TranslucencyAfterMotionBlur,
			TPT_TranslucencyHoldout,
			/** Drawing all translucency, regardless of separate or standard.  Used when drawing translucency outside of the main renderer, eg FRendererModule::DrawTile. */
			TPT_AllTranslucency,
			TPT_MAX
		};
	}
	enum EDepthDrawingMode
	{
		// tested at a higher level
		DDM_None			= 0,
		// Opaque materials only
		DDM_NonMaskedOnly	= 1,
		// Opaque and masked materials, but no objects with bUseAsOccluder disabled
		DDM_AllOccluders	= 2,
		// Full prepass, every object must be drawn and every pixel must match the base pass depth
		DDM_AllOpaque		= 3,
		// Masked materials only
		DDM_MaskedOnly = 4,
		// Full prepass, every object must be drawn and every pixel must match the base pass depth, except dynamic geometry which will render in the Velocity pass
		DDM_AllOpaqueNoVelocity	= 5,
	};
	enum EMaterialShadingModel : int
	{
		MSM_Unlit					UMETA(DisplayName="Unlit"),
		MSM_DefaultLit				UMETA(DisplayName="Default Lit"),
		MSM_Subsurface				UMETA(DisplayName="Subsurface"),
		MSM_PreintegratedSkin		UMETA(DisplayName="Preintegrated Skin"),
		MSM_ClearCoat				UMETA(DisplayName="Clear Coat"),
		MSM_SubsurfaceProfile		UMETA(DisplayName="Subsurface Profile"),
		MSM_TwoSidedFoliage			UMETA(DisplayName="Two Sided Foliage"),
		MSM_Hair					UMETA(DisplayName="Hair"),
		MSM_Cloth					UMETA(DisplayName="Cloth"),
		MSM_Eye						UMETA(DisplayName="Eye"),
		MSM_SingleLayerWater		UMETA(DisplayName="SingleLayerWater"),
		MSM_ThinTranslucent			UMETA(DisplayName="Thin Translucent"),
		MSM_Strata					UMETA(DisplayName="Substrate", Hidden),
		/** Number of unique shading models. */
		MSM_NUM						UMETA(Hidden),
		/** Shading model will be determined by the Material Expression Graph,
			by utilizing the 'Shading Model' MaterialAttribute output pin. */
		MSM_FromMaterialExpression	UMETA(DisplayName="From Material Expression"),
		MSM_MAX
	};
	struct FMaterialShadingModelField
	{
		EMaterialShadingModel ShadingModelField=MSM_Unlit;
	};
	enum class EShadingPath
	{
		Mobile,
		Deferred,
		Num,
	};
    struct TextureRenderTargetBinding
    {
        RDGTexture* Texture;
        int16 ArraySlice;
        bool bNeverClear;

        TextureRenderTargetBinding()
            : Texture(nullptr)
            , ArraySlice(-1)
            , bNeverClear(false)
        {}

        TextureRenderTargetBinding(RDGTexture* InTexture, bool bInNeverClear)
            : Texture(InTexture)
            , ArraySlice(-1)
            , bNeverClear(bInNeverClear)
        {}

        TextureRenderTargetBinding(RDGTexture* InTexture, int16 InArraySlice = -1, bool bInNeverClear = false)
            : Texture(InTexture)
            , ArraySlice(InArraySlice)
            , bNeverClear(bInNeverClear)
        {}
    };
    /** Render graph information about how to bind a render target. */
	struct RenderTargetBinding
	{
		RenderTargetBinding() = default;
		RenderTargetBinding(RDGTexture* InTexture, ERenderTargetLoadAction InLoadAction, uint8 InMipIndex = 0, int16 InArraySlice = -1)
			: Texture(InTexture)
			, LoadAction(InLoadAction)
			, MipIndex(InMipIndex)
			, ArraySlice(InArraySlice)
		{
		}

		RenderTargetBinding(RDGTexture* InTexture, RDGTexture* InResolveTexture, ERenderTargetLoadAction InLoadAction, uint8 InMipIndex = 0, int16 InArraySlice = -1)
			: Texture(InTexture)
			, ResolveTexture(InResolveTexture)
			, LoadAction(InLoadAction)
			, MipIndex(InMipIndex)
			, ArraySlice(InArraySlice)
		{
		}
		RDGTexture* GetTexture() const
		{
			return Texture;
		}
		RDGTexture* GetResolveTexture() const
		{
			return ResolveTexture;
		}
		ERenderTargetLoadAction GetLoadAction() const
		{
			return LoadAction;
		}

		uint8 GetMipIndex() const
		{
			return MipIndex;
		}

		int16 GetArraySlice() const
		{
			return ArraySlice;
		}

		/** Whether we can merge a render pass using Other into a render pass using this render target binding. */
		inline bool CanMergeBefore(const RenderTargetBinding& Other) const
		{
			return
				Texture == Other.Texture &&
				ResolveTexture == Other.ResolveTexture &&
				Other.LoadAction != ERenderTargetLoadAction::EClear &&
				MipIndex == Other.MipIndex &&
				ArraySlice == Other.ArraySlice;
		}

		void SetTexture(RDGTexture* InTexture)
		{
			Texture = InTexture;
		}

		void SetResolveTexture(RDGTexture* InTexture)
		{
			ResolveTexture = InTexture;
		}

		void SetLoadAction(ERenderTargetLoadAction InLoadAction)
		{
			LoadAction = InLoadAction;
		}

		void SetMipIndex(uint8 InMipIndex)
		{
			MipIndex = InMipIndex;
		}

		void SetArraySlice(int16 InArraySlice)
		{
			ArraySlice = InArraySlice;
		}
	private:
		/** Intentionally kept private to force setting the load action in the constructor. */
		RDGTexture* Texture		= nullptr;
		RDGTexture* ResolveTexture	= nullptr;
		ERenderTargetLoadAction		LoadAction		= ERenderTargetLoadAction::ENoAction;
		uint8						MipIndex		= 0;
		int16						ArraySlice		= -1;

		bool Validate() const;
	};
	/** Render graph information about how to bind a depth-stencil render target. */
	struct FDepthStencilBinding
	{
		FDepthStencilBinding() = default;

		/**
		 * Creates a render target binding informations for a depth/stencil texture.
		 *
		 * Notes: Load and store action are on explicit without default values, to force the user to not forget one of these.
		 */
		FORCEINLINE FDepthStencilBinding(
			CGITexture* InTexture,
			ERenderTargetLoadAction InDepthLoadAction,
			ERenderTargetLoadAction InStencilLoadAction,
			ExclusiveDepthStencil InDepthStencilAccess)
			: Texture(InTexture)
			, ResolveTexture(nullptr)
			, DepthLoadAction(InDepthLoadAction)
			, StencilLoadAction(InStencilLoadAction)
			, DepthStencilAccess(InDepthStencilAccess)
		{
		}

		FORCEINLINE FDepthStencilBinding(
			CGITexture* InTexture,
			CGITexture* InResolveTexture,
			ERenderTargetLoadAction InDepthLoadAction,
			ERenderTargetLoadAction InStencilLoadAction,
			ExclusiveDepthStencil InDepthStencilAccess)
			: Texture(InTexture)
			, ResolveTexture(InResolveTexture)
			, DepthLoadAction(InDepthLoadAction)
			, StencilLoadAction(InStencilLoadAction)
			, DepthStencilAccess(InDepthStencilAccess)
		{
		}

		FORCEINLINE FDepthStencilBinding(
			CGITexture* InTexture,
			ERenderTargetLoadAction InDepthLoadAction,
			ExclusiveDepthStencil InDepthStencilAccess)
			: Texture(InTexture)
			, ResolveTexture(nullptr)
			, DepthLoadAction(InDepthLoadAction)
			, DepthStencilAccess(InDepthStencilAccess)
		{
		}

		FORCEINLINE FDepthStencilBinding(
			CGITexture* InTexture,
			CGITexture* InResolveTexture,
			ERenderTargetLoadAction InDepthLoadAction,
			ExclusiveDepthStencil InDepthStencilAccess)
			: Texture(InTexture)
			, ResolveTexture(InResolveTexture)
			, DepthLoadAction(InDepthLoadAction)
			, DepthStencilAccess(InDepthStencilAccess)
		{
		}

		FORCEINLINE CGITexture* GetTexture() const
		{
			return Texture;
		}
		FORCEINLINE CGITexture* GetResolveTexture() const
		{
			return ResolveTexture;
		}
		FORCEINLINE ERenderTargetLoadAction GetDepthLoadAction() const
		{
			return DepthLoadAction;
		}
		FORCEINLINE ERenderTargetLoadAction GetStencilLoadAction() const
		{
			return StencilLoadAction;
		}
		FORCEINLINE ExclusiveDepthStencil GetDepthStencilAccess() const
		{
			return DepthStencilAccess;
		}

		// Whether we can merge a render pass using @ref Other into a render pass using this depth stencil binding.
		inline bool CanMergeBefore(const FDepthStencilBinding& Other) const
		{
			return
				Texture == Other.Texture &&
				ResolveTexture == Other.ResolveTexture &&
				Other.DepthLoadAction != ERenderTargetLoadAction::EClear &&
				Other.StencilLoadAction != ERenderTargetLoadAction::EClear &&
				DepthStencilAccess == Other.DepthStencilAccess;
		}

		void SetTexture(CGITexture* InTexture)
		{
			Texture = InTexture;
		}

		void SetResolveTexture(CGITexture* InTexture)
		{
			ResolveTexture = InTexture;
		}

		void SetDepthStencilAccess(ExclusiveDepthStencil InAccess)
		{
			DepthStencilAccess = InAccess;
		}

		void SetDepthLoadAction(ERenderTargetLoadAction InAction)
		{
			DepthLoadAction = InAction;
		}

		void SetStencilLoadAction(ERenderTargetLoadAction InAction)
		{
			StencilLoadAction = InAction;
		}

	private:
		/** 
		 * All parameters required to bind a depth render target deferred. This are purposefully private to
		 * force the user to call FDepthStencilBinding() constructors. No defaults allowed.
		 */
		CGITexture* Texture = nullptr;
		CGITexture* ResolveTexture = nullptr;
		ERenderTargetLoadAction		DepthLoadAction		= ERenderTargetLoadAction::ENoAction;
		ERenderTargetLoadAction		StencilLoadAction	= ERenderTargetLoadAction::ENoAction;
		ExclusiveDepthStencil		DepthStencilAccess	= ExclusiveDepthStencil::DepthNop_StencilNop;

		bool Validate() const;
	};
	/** Special shader parameters type for a pass parameter to setup render targets. */
	struct alignas(SHADER_PARAMETER_STRUCT_ALIGNMENT) RenderTargetBindingSlots
	{
		RenderTargetBinding Output[MaxSimultaneousRenderTargets];
		FDepthStencilBinding DepthStencil;
		FResolveRect ResolveRect;
		uint32 NumOcclusionQueries = 0;
		ESubpassHint SubpassHint = ESubpassHint::None;
		uint8 MultiViewCount = 0;
		CGITexture* ShadingRateTexture = nullptr;

		/** Accessors for regular output to simplify the syntax to:
		 *
		 *	FRenderTargetParameters PassParameters;
		 *	PassParameters.RenderTargets.DepthStencil = ... ;
		 *	PassParameters.RenderTargets[0] = ... ;
		 */
		RenderTargetBinding& operator[](uint32 Index)
		{
			return Output[Index];
		}

		const RenderTargetBinding& operator[](uint32 Index) const
		{
			return Output[Index];
		}

		template <typename TFunction>
		void Enumerate(TFunction Function)
		{
			for (int32 Index = 0; Index < Output.Num(); Index++)
			{
				if (Output[Index].GetTexture())
				{
					Function(Output[Index]);
				}
				else
				{
					break;
				}
			}
		}

		template <typename TFunction>
		void Enumerate(TFunction Function) const
		{
			for (int32 Index = 0; Index < Output.Num(); Index++)
			{
				if (Output[Index].GetTexture())
				{
					Function(Output[Index]);
				}
				else
				{
					break;
				}
			}
		}

		uint32 GetActiveCount() const
		{
			uint32 Count = 0;
			for (; Output[Count].GetTexture() != nullptr; ++Count) {};
			return Count;
		}

		bool CanMergeBefore(const RenderTargetBindingSlots& Other) const
		{
			for (int32 Index = 0; Index < MaxSimultaneousRenderTargets; ++Index)
			{
				if (!Output[Index].CanMergeBefore(Other.Output[Index]))
				{
					return false;
				}
			}

			if (!DepthStencil.CanMergeBefore(Other.DepthStencil))
			{
				return false;
			}

			if (ResolveRect != Other.ResolveRect ||
				(NumOcclusionQueries != Other.NumOcclusionQueries && Other.NumOcclusionQueries != 0) ||
				SubpassHint != Other.SubpassHint ||
				MultiViewCount != Other.MultiViewCount ||
				ShadingRateTexture != Other.ShadingRateTexture)
			{
				return false;
			}

			return true;
		}

		struct FTypeInfo
		{
			static constexpr int32 NumRows = 1;
			static constexpr int32 NumColumns = 1;
			static constexpr int32 NumElements = 0;
			static constexpr int32 Alignment = SHADER_PARAMETER_STRUCT_ALIGNMENT;
			static constexpr bool bIsStoredInConstantBuffer = false;

			using TAlignedType = RenderTargetBindingSlots;
		};
	};
	inline RenderTargetBindingSlots GetRenderTargetBindings(ERenderTargetLoadAction ColorLoadAction, std::vector<TextureRenderTargetBinding> ColorTextures)
	{
		RenderTargetBindingSlots BindingSlots;
		for (int32 Index = 0, Count = ColorTextures.size(); Index < Count; ++Index)
		{
			BindingSlots[Index] = RenderTargetBinding(ColorTextures[Index].Texture, ColorLoadAction, 0, ColorTextures[Index].ArraySlice);
			if (ColorLoadAction == ERenderTargetLoadAction::EClear && ColorTextures[Index].bNeverClear)
			{
				BindingSlots[Index].SetLoadAction(ERenderTargetLoadAction::ELoad);
			}
		}
		return BindingSlots;
	}
    /** Flags to annotate a pass with when calling AddPass. */
    enum class ERDGPassFlags : uint16
    {
        /** Pass doesn't have any inputs or outputs tracked by the graph. This may only be used by the parameterless AddPass function. */
        None = 0,

        /** Pass uses rasterization on the graphics pipe. */
        Raster = 1 << 0,

        /** Pass uses compute on the graphics pipe. */
        Compute = 1 << 1,

        /** Pass uses compute on the async compute pipe. */
        AsyncCompute = 1 << 2,

        /** Pass uses copy commands on the graphics pipe. */
        Copy = 1 << 3,

        /** Pass (and its producers) will never be culled. Necessary if outputs cannot be tracked by the graph. */
        NeverCull = 1 << 4,

        /** Render pass begin / end is skipped and left to the user. Only valid when combined with 'Raster'. Disables render pass merging for the pass. */
        SkipRenderPass = 1 << 5,

        /** Pass will never have its render pass merged with other passes. */
        NeverMerge = 1 << 6,

        /** Pass will never run off the render thread. */
        NeverParallel = 1 << 7,

        /** Pass uses copy commands but writes to a staging resource. */
        Readback = Copy | NeverCull
    };
    ENUM_CLASS_FLAGS(ERDGPassFlags)
	enum ELightMapPolicyType
    {
    	LMP_NO_LIGHTMAP,
		LMP_PRECOMPUTED_IRRADIANCE_VOLUME_INDIRECT_LIGHTING,
		LMP_CACHED_VOLUME_INDIRECT_LIGHTING,
		LMP_CACHED_POINT_INDIRECT_LIGHTING,
		LMP_LQ_LIGHTMAP,
		LMP_HQ_LIGHTMAP,
		LMP_DISTANCE_FIELD_SHADOWS_AND_HQ_LIGHTMAP,
		// Mobile specific
		LMP_MOBILE_DISTANCE_FIELD_SHADOWS_AND_LQ_LIGHTMAP,
		LMP_MOBILE_DISTANCE_FIELD_SHADOWS_LIGHTMAP_AND_CSM,
		LMP_MOBILE_DIRECTIONAL_LIGHT_CSM_AND_LIGHTMAP,
		LMP_MOBILE_DIRECTIONAL_LIGHT_AND_SH_INDIRECT,
		LMP_MOBILE_DIRECTIONAL_LIGHT_CSM_AND_SH_INDIRECT,
		LMP_MOBILE_DIRECTIONAL_LIGHT_CSM,

		// LightMapDensity
		LMP_DUMMY
	};
	enum EGBufferLayout
	{
		GBL_Default, // Default GBuffer Layout
		GBL_ForceVelocity, // Force the inclusion of the velocity target (if it's not included in GBL_Default)

		GBL_Num
	};
	// Constants.
	enum { MAX_STATIC_TEXCOORDS = 8 };
	/** The information used to build a static-mesh vertex. */
	struct StaticMeshBuildVertex
	{
		Vector3f mPosition;

		Vector3f mTangentX;
		Vector3f mTangentY;
		Vector3f mTangentZ;

		Vector2f mUVs[MAX_STATIC_TEXCOORDS];
		Color mColor;
	};
	struct BasePassParameter
    {
    	RenderTargetBindingSlots mRenderTargetBindingSlots;
    	bool mbIsSwapChain;
    	uint32 mbSwapChainImageIndex;
    };
	
	/** Mesh pass types supported. */
	namespace EMeshPass
	{
		enum Type : uint8
		{
			DepthPass,
			SecondStageDepthPass,
			BasePass,
			AnisotropyPass,
			SkyPass,
			SingleLayerWaterPass,
			SingleLayerWaterDepthPrepass,
			CSMShadowDepth,
			VSMShadowDepth,
			OnePassPointLightShadowDepth,
			Distortion,
			Velocity,
			TranslucentVelocity,
			TranslucencyStandard,
			TranslucencyStandardModulate,
			TranslucencyAfterDOF,
			TranslucencyAfterDOFModulate,
			TranslucencyAfterMotionBlur,
			TranslucencyHoldout, /** A standalone pass to render all translucency for holdout, inferring the background visibility*/
			TranslucencyAll, /** Drawing all translucency, regardless of separate or standard.  Used when drawing translucency outside of the main renderer, eg FRendererModule::DrawTile. */
			LightmapDensity,
			DebugViewMode, /** Any of EDebugViewShaderMode */
			CustomDepth,
			MobileBasePassCSM,  /** Mobile base pass with CSM shading enabled */
			VirtualTexture,
			LumenCardCapture,
			LumenCardNanite,
			LumenTranslucencyRadianceCacheMark,
			LumenFrontLayerTranslucencyGBuffer,
			DitheredLODFadingOutMaskPass, /** A mini depth pass used to mark pixels with dithered LOD fading out. Currently only used by ray tracing shadows. */
			NaniteMeshPass,
			MeshDecal_DBuffer,
			MeshDecal_SceneColorAndGBuffer,
			MeshDecal_SceneColorAndGBufferNoNormal,
			MeshDecal_SceneColor,
			MeshDecal_AmbientOcclusion,
			WaterInfoTextureDepthPass,
			WaterInfoTexturePass,

	#if WITH_EDITOR
			HitProxy,
			HitProxyOpaqueOnly,
			EditorLevelInstance,
			EditorSelection,
	#endif

			Num,
			NumBits = 6,
		};
	}
	static_assert(EMeshPass::Num <= (1 << EMeshPass::NumBits), "EMeshPass::Num will not fit in EMeshPass::NumBits");
	static_assert(EMeshPass::NumBits <= sizeof(EMeshPass::Type) * 8, "EMeshPass::Type storage is too small");

	inline const TCHAR* GetMeshPassName(EMeshPass::Type MeshPass)
	{
		switch (MeshPass)
		{
		case EMeshPass::DepthPass: return TEXT("DepthPass");
		case EMeshPass::SecondStageDepthPass: return TEXT("SecondStageDepthPass");
		case EMeshPass::BasePass: return TEXT("BasePass");
		case EMeshPass::AnisotropyPass: return TEXT("AnisotropyPass");
		case EMeshPass::SkyPass: return TEXT("SkyPass");
		case EMeshPass::SingleLayerWaterPass: return TEXT("SingleLayerWaterPass");
		case EMeshPass::SingleLayerWaterDepthPrepass: return TEXT("SingleLayerWaterDepthPrepass");
		case EMeshPass::CSMShadowDepth: return TEXT("CSMShadowDepth");
		case EMeshPass::VSMShadowDepth: return TEXT("VSMShadowDepth");
		case EMeshPass::OnePassPointLightShadowDepth: return TEXT("OnePassPointLightShadowDepth");
		case EMeshPass::Distortion: return TEXT("Distortion");
		case EMeshPass::Velocity: return TEXT("Velocity");
		case EMeshPass::TranslucentVelocity: return TEXT("TranslucentVelocity");
		case EMeshPass::TranslucencyStandard: return TEXT("TranslucencyStandard");
		case EMeshPass::TranslucencyStandardModulate: return TEXT("TranslucencyStandardModulate");
		case EMeshPass::TranslucencyAfterDOF: return TEXT("TranslucencyAfterDOF");
		case EMeshPass::TranslucencyAfterDOFModulate: return TEXT("TranslucencyAfterDOFModulate");
		case EMeshPass::TranslucencyAfterMotionBlur: return TEXT("TranslucencyAfterMotionBlur");
		case EMeshPass::TranslucencyHoldout: return TEXT("TranslucencyHoldout");
		case EMeshPass::TranslucencyAll: return TEXT("TranslucencyAll");
		case EMeshPass::LightmapDensity: return TEXT("LightmapDensity");
		case EMeshPass::DebugViewMode: return TEXT("DebugViewMode");
		case EMeshPass::CustomDepth: return TEXT("CustomDepth");
		case EMeshPass::MobileBasePassCSM: return TEXT("MobileBasePassCSM");
		case EMeshPass::VirtualTexture: return TEXT("VirtualTexture");
		case EMeshPass::LumenCardCapture: return TEXT("LumenCardCapture");
		case EMeshPass::LumenCardNanite: return TEXT("LumenCardNanite");
		case EMeshPass::LumenTranslucencyRadianceCacheMark: return TEXT("LumenTranslucencyRadianceCacheMark");
		case EMeshPass::LumenFrontLayerTranslucencyGBuffer: return TEXT("LumenFrontLayerTranslucencyGBuffer");
		case EMeshPass::DitheredLODFadingOutMaskPass: return TEXT("DitheredLODFadingOutMaskPass");
		case EMeshPass::NaniteMeshPass: return TEXT("NaniteMeshPass");
		case EMeshPass::MeshDecal_DBuffer: return TEXT("MeshDecal_DBuffer");
		case EMeshPass::MeshDecal_SceneColorAndGBuffer: return TEXT("MeshDecal_SceneColorAndGBuffer");
		case EMeshPass::MeshDecal_SceneColorAndGBufferNoNormal: return TEXT("MeshDecal_SceneColorAndGBufferNoNormal");
		case EMeshPass::MeshDecal_SceneColor: return TEXT("MeshDecal_SceneColor");
		case EMeshPass::MeshDecal_AmbientOcclusion: return TEXT("MeshDecal_AmbientOcclusion");
		case EMeshPass::WaterInfoTextureDepthPass: return TEXT("WaterInfoTextureDepthPass");
		case EMeshPass::WaterInfoTexturePass: return TEXT("WaterInfoTexturePass");
	#if WITH_EDITOR
		case EMeshPass::HitProxy: return TEXT("HitProxy");
		case EMeshPass::HitProxyOpaqueOnly: return TEXT("HitProxyOpaqueOnly");
		case EMeshPass::EditorLevelInstance: return TEXT("EditorLevelInstance");
		case EMeshPass::EditorSelection: return TEXT("EditorSelection");
	#endif
		}

	#if WITH_EDITOR
		static_assert(EMeshPass::Num == 38 + 4, "Need to update switch(MeshPass) after changing EMeshPass"); // GUID to prevent incorrect auto-resolves, please change when changing the expression: {674D7D62-CFD8-4971-9A8D-CD91E5612CD8}
	#else
		static_assert(EMeshPass::Num == 38, "Need to update switch(MeshPass) after changing EMeshPass"); // GUID to prevent incorrect auto-resolves, please change when changing the expression: {674D7D62-CFD8-4971-9A8D-CD91E5612CD8}
	#endif

		checkf(0, TEXT("Missing case for EMeshPass %u"), (uint32)MeshPass);
		return nullptr;
	}

	/** Mesh pass mask - stores one bit per mesh pass. */
	class FMeshPassMask
	{
	public:
		FMeshPassMask()
			: Data(0)
		{
		}

		void Set(EMeshPass::Type Pass) 
		{ 
			Data |= (uint64(1) << Pass); 
		}

		bool Get(EMeshPass::Type Pass) const 
		{ 
			return !!(Data & (uint64(1) << Pass)); 
		}

		EMeshPass::Type SkipEmpty(EMeshPass::Type Pass) const 
		{
			uint64 Mask = 0xFFffFFffFFffFFffULL << Pass;
			return EMeshPass::Type(MathUtils::Min<uint64>(EMeshPass::Num, MathUtils::CountTrailingZeros64(Data & Mask)));
		}

		int GetNum() 
		{ 
			return MathUtils::CountBits(Data); 
		}

		void AppendTo(FMeshPassMask& Mask) const 
		{ 
			Mask.Data |= Data; 
		}

		void Reset() 
		{ 
			Data = 0; 
		}

		bool IsEmpty() const 
		{ 
			return Data == 0; 
		}

		uint64 Data;
	};
}
